package memory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Set;



public class MemorySimulation{
    private HashMap<Integer, Integer> myMemory;
    private int myMaxLocation;

    /**
      * creates a memory simulator with the default size (32 kb)
      */
    public MemorySimulation(){
        this(32768);
    }

    /**
      * creates a memory simulator with user defined size
      *
      * @param size the desired size in bytes of your simulated memory
      */
    public MemorySimulation(int size){
        myMemory = new HashMap<Integer, Integer>();
        myMaxLocation=size;
    }

    /** 
      * gets the integer at a table location. 
      * Throws a MEMORYOUTOFBOUNDS error if the location is too high.
      * Throws a LOCATIONNOTINITIALIZED error if the memory location
      * has not been explicitly defined.
      * 
      * @param the memory location you want to retrieve the value of
      * @return the value stored at that memory location
      */
    public int get(int location)
    {
        validateLocation(location);
        if(myMemory.get(location)!=null){
            return myMemory.get(location);
        }
        throw new MemoryException( 
           "This location has not yet been initialized!" );
    }
    
    /** 
      * sets the integer at a table location. Throws a MEMORYOUTOFBOUNDS
      * error if the location is too high.
      */
    public void set(int location, int value)
    {
        validateLocation(location);
        myMemory.put(location, value);
    }
    
    /** 
      * gets the integers between two table locations. Throws a
      * MEMORYOUTOFBOUNDS error if one of the locations is too high.
      *
      * @return an arraylist of values between the two locations, 
      * empty if there are none.
      */
    public ArrayList<Integer> get(int startLocation, int endLocation)
    {
        validateLocation(startLocation);
        validateLocation(endLocation);
        Set<Integer> locations = myMemory.keySet();
        ArrayList<Integer> toReturn = new ArrayList<Integer>();
        for(Integer i: locations){
            if(i>=startLocation&&i<=endLocation){
                toReturn.add(myMemory.get(i));
            }
        }
        return toReturn;
    }
    
    /** 
      * sets the integers from a table location. Throws a MEMORYOUTOFBOUNDS
      * error if one of the locations is too high.
      */
    public void set(int location, int[] values)
    {
        validateLocation(location);
        validateLocation(location+values.length-1);
        for (int i=location; i<location+values.length; i++){
            myMemory.put(i, values[i-location]);
        }
    }
    
    /**
      * Throws an error if your memory location is out of bounds.
      * ... terminate program too??
      */
    private void validateLocation(int location)
    {
        if(location>=myMaxLocation||location<0)
        {
            throw new MemoryException( 
                "This memory value is out of bounds." );
            //TODO: terminate program
        }
        
    }
}